{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import os\n",
    "import re\n",
    "\n",
    "import numpy as np"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "import matplotlib.pyplot as plt\n",
    "from pylab import *"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "from pythonlib import boolean as boolean\n",
    "from pythonlib import boolean_net as boolean_net"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "import random as random #random could be destroyed by matplotlib"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "def to_bool_charactor(c):\n",
    "    if c=='1':\n",
    "        return True\n",
    "    else:\n",
    "        return False"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "def to_bool_string(s):\n",
    "    return[to_bool_charactor(x) for x in s]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "def file2matrix(path):\n",
    "    fp=open(path,'r')\n",
    "    content=fp.read()\n",
    "    rowlist=content.splitlines()\n",
    "    x=np.array([to_bool_string(x) for x in rowlist])\n",
    "    \n",
    "    return x\n",
    "    "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "def show_nn(bl1):\n",
    "    fig,axs=plt.subplots(nrows=1, ncols=5, figsize=(12, 6))\n",
    "    axs[0].imshow(np.array([bl1.inode]),vmin=0,vmax=1)\n",
    "    axs[0].set_title('inode')\n",
    "    axs[0].set_axis_off()\n",
    "    axs[1].imshow(bl1.wi,vmin=0,vmax=1)\n",
    "    axs[1].set_title('wi')\n",
    "    axs[1].set_axis_off()\n",
    "    axs[2].imshow(np.array([bl1.hnode]),vmin=0,vmax=1)\n",
    "    axs[2].set_title('hnode')\n",
    "    axs[2].set_axis_off()\n",
    "    axs[3].imshow(bl1.wo,vmin=0,vmax=1)\n",
    "    axs[3].set_title('wo')\n",
    "    axs[3].set_axis_off()\n",
    "    axs[4].imshow(np.array([bl1.onode]),vmin=0,vmax=1)\n",
    "    axs[4].set_title('onode')\n",
    "    axs[4].set_axis_off()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "def show_nparray(nparray):\n",
    "    fig,axs=plt.subplots(nrows=1, ncols=1)\n",
    "    axs.imshow((nparray),vmin=0,vmax=1)\n",
    "    axs.set_title('array')\n",
    "    axs.set_axis_off()\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [],
   "source": [
    "def to_char_bool(bool):\n",
    "    if bool:\n",
    "        return '1'\n",
    "    else:\n",
    "        return '0'\n",
    "\n",
    "def to_string_boollist(boollist):\n",
    "    temp=[to_char_bool(x) for x in boollist]    \n",
    "    return ''.join(temp)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [],
   "source": [
    "#target_set=[0,1,2,3]\n",
    "#target_set=[0,1,2,3,4]\n",
    "root = \"trainingDigits16x\" #数据文件所在路径\\n\"\n",
    "pathlist = os.listdir(root) # 获取路径下所有数据文件\"\n",
    "t=4\n",
    "random.shuffle(pathlist)\n",
    "test_set=[]\n",
    "for i in range (0,64):\n",
    "    filepath=root+'\\\\'+pathlist[i]\n",
    "    s=pathlist[i]\n",
    "    n=(re.split('_',s))[0]\n",
    "    if int(n)==t:\n",
    "        target=[True]\n",
    "\n",
    "    else:\n",
    "        target=[False]\n",
    "    input=file2matrix(filepath).flatten().tolist()\n",
    "    #print(filepath)\n",
    "    test_set.append([input,target])\n",
    "    \n",
    "random.shuffle(pathlist)\n",
    "verify_set=[]\n",
    "for i in range (0,64):\n",
    "    filepath=root+'\\\\'+pathlist[i]\n",
    "    s=pathlist[i]\n",
    "    n=(re.split('_',s))[0]\n",
    "    if int(n)==t:\n",
    "        target=[True]\n",
    "\n",
    "    else:\n",
    "        target=[False]\n",
    "    input=file2matrix(filepath).flatten().tolist()\n",
    "    #print(filepath)\n",
    "    verify_set.append([input,target])\n",
    "     "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "target:  [True]   result:  [False]  wrong\n",
      "target:  [True]   result:  [False]  wrong\n",
      "target:  [True]   result:  [False]  wrong\n",
      "target:  [False]   result:  [True]  wrong\n",
      "target:  [False]   result:  [True]  wrong\n",
      "target:  [False]   result:  [True]  wrong\n",
      "target:  [False]   result:  [True]  wrong\n",
      "57\n",
      "[[False], [False], [False], [False], [False], [False], [False], [False], [False], [False], [True], [False], [False], [False], [False], [False], [False], [False], [False], [False], [False], [False], [True], [False], [False], [False], [False], [False], [False], [False], [False], [False], [False], [False], [False], [False], [False], [False], [False], [False], [False], [False], [False], [False], [False], [False], [False], [False], [False], [False], [True], [False], [False], [False], [False], [False], [False]]\n"
     ]
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 864x432 with 5 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "\n",
    "bl1=boolean_net.booleannet('bl.db',256,2,1)\n",
    "bl1_mirr=boolean_net.booleannet('bl.db',1,2,256)\n",
    "random.shuffle(test_set)\n",
    "#train\n",
    "for i in test_set:   \n",
    "    bl1.train(i[0],i[1])\n",
    "    bl1.feedforward()\n",
    "    #copy from origin nn weight\n",
    "    bl1_mirr.wi=bl1.wo.T\n",
    "    bl1_mirr.wo=bl1.wi.T\n",
    "\n",
    "    bl1_mirr.train(i[1],i[0])\n",
    "\n",
    "    bl1_mirr.feedforward()\n",
    "     #copy back origin nn weight\n",
    "    #bl1.wi=bl1_mirr.wo.T\n",
    "    bl1.wo=bl1_mirr.wi.T   \n",
    "\n",
    "#test\n",
    "right=0\n",
    "right_list=[]\n",
    "max=0\n",
    "max_right_list=[]\n",
    "for i in verify_set:\n",
    "    bl1.inode=i[0]\n",
    "    bl1.feedforward()\n",
    "    if bl1.onode==i[1]:\n",
    "        #print('target: ',i[1] , '  result: ',bl1.onode,' right')\n",
    "        right_list.append(bl1.onode)\n",
    "        right+=1\n",
    "    else:\n",
    "        #pass\n",
    "        print('target: ',i[1]  , '  result: ',bl1.onode,' wrong')\n",
    "    if right>max:\n",
    "        max=right\n",
    "        max_right_list=right_list\n",
    "        bl_max=bl1\n",
    "print (max)\n",
    "print(max_right_list)\n",
    "show_nn(bl_max)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "ename": "NameError",
     "evalue": "name 'bool_list' is not defined",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mNameError\u001b[0m                                 Traceback (most recent call last)",
      "\u001b[1;32m<ipython-input-17-97aec1be957a>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[0;32m     17\u001b[0m         \u001b[0mbl1\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0minode\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0mi\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;36m0\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     18\u001b[0m         \u001b[0mbl1\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mfeedforward\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 19\u001b[1;33m         \u001b[0mtarget\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mbool_list\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mindex\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mi\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;36m1\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m     20\u001b[0m         \u001b[1;32mtry\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     21\u001b[0m             \u001b[0mresult\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mbool_list\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mindex\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mbl1\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0monode\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;31mNameError\u001b[0m: name 'bool_list' is not defined"
     ]
    }
   ],
   "source": [
    "\n",
    "for j in range(0,12):\n",
    "    bl1=boolean_net.booleannet('bl.db',256,16,4)\n",
    "    random.shuffle(test_set)\n",
    "        #train\n",
    "    #train\n",
    "    for i in test_set:   \n",
    "        bl1.train(i[0],i[1])\n",
    "        bl1.feedforward()\n",
    "\n",
    "    #test\n",
    "    right=0\n",
    "    right_list=[]\n",
    "    max=0\n",
    "    max_right_list=[]\n",
    "    for i in verify_set:\n",
    "        bl1.inode=i[0]\n",
    "        bl1.feedforward()\n",
    "        target = bool_list.index(i[1])\n",
    "        try:\n",
    "            result = bool_list.index(bl1.onode)\n",
    "        except:\n",
    "            result ='not_in_list'\n",
    "        #print()    \n",
    "        if bl1.onode==i[1]:\n",
    "            #print('target: ',target , '  result: ',result,' right')\n",
    "            right_list.append(target)\n",
    "            right+=1\n",
    "        else:\n",
    "            pass\n",
    "            #print('target: ',target , '  result: ',result,' wrong')\n",
    "        if right>max:\n",
    "            max=right\n",
    "            max_right_list=right_list\n",
    "            bl_max=bl1\n",
    "    print (max)\n",
    "    print(max_right_list)\n",
    "    show_nn(bl_max)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 79,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "63"
      ]
     },
     "execution_count": 79,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "len(verify_set)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 80,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "63"
      ]
     },
     "execution_count": 80,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "len(test_set)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [],
   "source": [
    "#double hidden node neural network\n",
    "bl1=boolean_net.booleannet('bl.db',256,16,8)\n",
    "bl2=boolean_net.booleannet('bl.db',8,8,4)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {},
   "outputs": [],
   "source": [
    "#train for net with 2 hidenode\n",
    "for i in test_set: \n",
    "    bl1.inode=i[0]\n",
    "    bl1.feedforward()\n",
    "    bl2.inode=bl1.onode\n",
    "    bl2.feedforward()\n",
    "    #backPropagate\n",
    "    bl2.backPropagate(i[1])\n",
    "    bl1.backPropagate(bl2.inode)\n",
    "    "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "target:  9   result:  2  wrong\n",
      "target:  6   result:  2  wrong\n",
      "target:  0   result:  not_in_list  wrong\n",
      "target:  1   result:  7  wrong\n",
      "target:  8   result:  2  wrong\n",
      "target:  3   result:  not_in_list  wrong\n",
      "target:  2   result:  7  wrong\n",
      "target:  9   result:  2  wrong\n",
      "target:  3   result:  2  wrong\n",
      "target:  1   result:  not_in_list  wrong\n",
      "target:  9   result:  2  wrong\n",
      "target:  8   result:  not_in_list  wrong\n",
      "target:  4   result:  2  wrong\n",
      "target:  5   result:  2  wrong\n",
      "target:  6   result:  2  wrong\n",
      "target:  1   result:  6  wrong\n",
      "target:  8   result:  2  wrong\n",
      "target:  8   result:  0  wrong\n",
      "target:  2   result:  2  right\n",
      "target:  9   result:  2  wrong\n",
      "target:  6   result:  3  wrong\n",
      "target:  2   result:  6  wrong\n",
      "target:  5   result:  not_in_list  wrong\n",
      "target:  2   result:  2  right\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "2"
      ]
     },
     "execution_count": 30,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#test\n",
    "right=0\n",
    "right=0\n",
    "right_list=[]\n",
    "for i in verify_set:\n",
    "    bl1.inode=i[0]\n",
    "    bl1.feedforward()\n",
    "    bl2.inode=bl1.onode\n",
    "    bl2.feedforward()\n",
    "    target = bool_list.index(i[1])\n",
    "    try:\n",
    "        result = bool_list.index(bl2.onode)\n",
    "    except:\n",
    "        result ='not_in_list'\n",
    "    #print()    \n",
    "    if bl2.onode==i[1]:\n",
    "        print('target: ',target , '  result: ',result,' right')\n",
    "        right_list.append(target)\n",
    "        right+=1\n",
    "    else:\n",
    "        print('target: ',target , '  result: ',result,' wrong')\n",
    "\n",
    "right"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[2, 2]"
      ]
     },
     "execution_count": 31,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "right_list"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {},
   "outputs": [],
   "source": [
    "x=(np.random.rand(3,3))>0.5"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {},
   "outputs": [],
   "source": [
    "x=np.array([[1,0,1],[0,1,0],[1,0,1]])>0.5"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {},
   "outputs": [],
   "source": [
    "x=np.array([[0,1,0],[1,0,1],[0,1,0]])>0.5"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAPUAAAEICAYAAACHyrIWAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDMuMC4xLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvDW2N/gAABZlJREFUeJzt3D2IpdUdx/Hff9lOkixERFeMRbAQjCwpTCWpwlrYpBCbRWJvJQiWWgQrTcAylfiCsonYWCwLKQISEIQtRARfIAmOCb6wvoAKsifF3GJjxuwuzuzc/Px8quE8zz1zHrhfzoG5c2etFaDHkcNeALC/RA1lRA1lRA1lRA1lRA1lRA1lRA1lRP09NDNHL2eM/0+iLjIzD8/MOzPz2cy8MTO/3oz/ZmZemZnfzczHSR75lrGfzsyfZ+ajmflwZp6dmWObOR6amT994/c9OTO/v/pPyv8i6i7vJLkzyY+SPJrkmZm5YXPtF0neTXJdkt9+y9gkeSzJ8SS3JrkpySObe59JctdFkR9Ncm+Spw/0ibhioi6y1jq91tpZa11Ya72Q5K0kd2wu76y1nlxrfb3W+mKvsbXW22uts2utr9ZaHyR5IskvN3O/n+QvSe7ZvPauJB+utV67ek/I5RB1kZm5b2bOzcz5mTmf5LYk124u/2OPl/zH2MxcNzPPz8x7M/Npdnfnay+65akkpzY/n4pdeiuJusTM3JzkD0keSPLjtdaxJK9n90idJHv9O943xx7bjN2+1vphdsOdi66/lOT2mbktyd1Jnt2/J2C/iLrHNdkN8oMkmZn7s7tTX4kfJPk8yfmZuTHJQxdfXGt9meSPSZ5L8upa6+/fddHsP1GXWGu9keTxJH9N8q8kP0vyyhVO82iSnyf5JMnLSV7c456nNnM7em+p8SUJXImZ+UmSN5Ncv9b69LDXw3+zU3PZZuZIkgeTPC/o7eVTRFyWmbkmu8f6v2X3z1lsKcdvKOP4DWUO5Pj9qyP32P4v4czOucNewlY7efzEYS9h6529cHr2GrdTQxlRQxlRQxlRQxlRQxlRQxlRQxlRQxlRQxlRQxlRQxlRQxlRQxlRQxlRQxlRQxlRQxlRQxlRQxlRQxlRQxlRQxlRQxlRQxlRQxlRQxlRQxlRQxlRQxlRQxlRQxlRQxlRQxlRQxlRQxlRQxlRQxlRQxlRQxlRQxlRQxlRQxlRQxlRQxlRQxlRQxlRQxlRQxlRQxlRQxlRQxlRQxlRQxlRQxlRQxlRQxlRQxlRQxlRQxlRQxlRQxlRQxlRQxlRQxlRQxlRQxlRQxlRQxlRQxlRQxlRQxlRQ5lZa+37pBf+ecv+T1rm5PETh72ErXZm59xhL2HrHbn+rdlz/GovBDhYooYyooYyooYyooYyooYyooYyooYyooYyooYyooYyooYyooYyooYyooYyooYyooYyooYyooYyooYyooYyooYyooYyooYyooYyooYyooYyooYyooYyooYyooYyooYyooYyooYyooYyooYyooYyooYyooYyooYyooYyooYyooYyooYyooYyooYyooYyooYyooYyooYyooYyooYyooYyooYyooYyooYyooYyooYyooYyooYyooYyooYyooYyooYyooYyooYyooYyooYyooYyooYyooYyRw9i0pPHTxzEtFXO7Jw77CVsNe+hSzt7Ye9xOzWUETWUETWUETWUETWUETWUETWUETWUETWUETWUETWUETWUETWUETWUETWUETWUETWUETWUETWUETWUETWUETWUETWUETWUETWUETWUETWUETWUETWUETWUETWUETWUETWUETWUETWUETWUETWUETWUETWUETWUETWUETWUETWUETWUETWUETWUETWUETWUETWUETWUETWUETWUETWUETWUETWUETWUETWUETWUETWUETWUETWUETWUETWUETWUETWUETWUETWUETWUETWUETWUETWUETWUmbXWYa8B2Ed2aigjaigjaigjaigjaigjaigjaigjaigjaigjaigjaigjaigjaigjaigjaigjaigjaigjaigjaigjaigjaigjaigjaijzb0+Yv70yWM3YAAAAAElFTkSuQmCC\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "mask=np.repeat((np.repeat(x,2,axis=0)),2,axis=1)\n",
    "show_nparray(mask)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {},
   "outputs": [],
   "source": [
    "bl1=boolean_net.booleannet('bl.db',121,8,4)\n",
    "#convolution  + booleannet\n",
    "#train\n",
    "random.shuffle(test_set)\n",
    "for i in test_set:   \n",
    "    temp=np.array(i[0]).reshape(16,16)\n",
    "    res=boolean.convolution(boolean.otimes_bv_bv,temp,mask)\n",
    "    res=res.reshape(1,121).tolist()[0]\n",
    "    bl1.train(res,i[1])\n",
    "    bl1.feedforward()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "target:  9   result:  2  wrong\n",
      "target:  6   result:  0  wrong\n",
      "target:  0   result:  not_in_list  wrong\n",
      "target:  1   result:  6  wrong\n",
      "target:  8   result:  7  wrong\n",
      "target:  3   result:  3  right\n",
      "target:  2   result:  7  wrong\n",
      "target:  9   result:  7  wrong\n",
      "target:  3   result:  not_in_list  wrong\n",
      "target:  1   result:  0  wrong\n",
      "target:  9   result:  9  right\n",
      "target:  8   result:  3  wrong\n",
      "target:  4   result:  6  wrong\n",
      "target:  5   result:  not_in_list  wrong\n",
      "target:  6   result:  7  wrong\n",
      "target:  1   result:  7  wrong\n",
      "target:  8   result:  not_in_list  wrong\n",
      "target:  8   result:  6  wrong\n",
      "target:  2   result:  8  wrong\n",
      "target:  9   result:  9  right\n",
      "target:  6   result:  8  wrong\n",
      "target:  2   result:  0  wrong\n",
      "target:  5   result:  not_in_list  wrong\n",
      "target:  2   result:  1  wrong\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "3"
      ]
     },
     "execution_count": 37,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#test\n",
    "right=0\n",
    "right_list=[]\n",
    "for i in verify_set:\n",
    "    temp=np.array(i[0]).reshape(16,16)\n",
    "    res=boolean.convolution(boolean.otimes_bv_bv,temp,mask)\n",
    "    res=res.reshape(1,121).tolist()[0]   \n",
    "    bl1.inode=res\n",
    "    bl1.feedforward()\n",
    "    target = bool_list.index(i[1])\n",
    "    try:\n",
    "        result = bool_list.index(bl1.onode)\n",
    "    except:\n",
    "        result ='not_in_list'\n",
    "    #print()    \n",
    "    if bl1.onode==i[1]:\n",
    "        print('target: ',target , '  result: ',result,' right')\n",
    "        right_list.append(target)\n",
    "        right+=1\n",
    "    else:\n",
    "        print('target: ',target , '  result: ',result,' wrong')\n",
    "right\n",
    "    "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[3, 9, 9]"
      ]
     },
     "execution_count": 38,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "right_list"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "metadata": {},
   "outputs": [],
   "source": [
    "def multi_convolution(oa,mask_set):\n",
    "    rz=len(mask_set)\n",
    "    rx,ry=oa.shape\n",
    "    mx,my=mask_set[0].shape\n",
    "    \n",
    "    rx=rx-mx+1\n",
    "    ry=ry-my+1\n",
    "    temp=np.ones((rz,rx,ry))>0  \n",
    "    n=0\n",
    "\n",
    "    for i in mask_set:\n",
    "        res=boolean.convolution(boolean.otimes_bv_bv,oa,i)\n",
    "        #show_nparray(res)\n",
    "        temp[n]=res\n",
    "        n=n+1\n",
    "    return temp"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 209,
   "metadata": {},
   "outputs": [],
   "source": [
    "mask_set=[]\n",
    "for i in range (0,10):\n",
    "    x=(np.random.rand(3,3))>0.5\n",
    "    mask=np.repeat((np.repeat(x,4,axis=0)),4,axis=1)\n",
    "    mask_set.append(mask)\n",
    "    #show_nparray(mask)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 601,
   "metadata": {},
   "outputs": [],
   "source": [
    "m1=np.array([[0,0,0],\n",
    "             [1,1,1],\n",
    "             [0,0,0]])\n",
    "m2=np.array([[0,1,0],\n",
    "             [0,1,0],\n",
    "             [0,1,0]])\n",
    "m3=np.array([[1,0,0],\n",
    "             [0,1,0],\n",
    "             [0,0,1]])\n",
    "m4=np.array([[0,0,1],\n",
    "             [0,1,0],\n",
    "             [1,0,0]])\n",
    "m5=np.array([[1,0,1],\n",
    "             [0,1,0],\n",
    "             [1,0,1]])\n",
    "m6=np.array([[1,1,1],\n",
    "             [1,0,0],\n",
    "             [1,0,0]])\n",
    "m7=np.array([[1,1,1],\n",
    "             [0,0,1],\n",
    "             [0,0,1]])\n",
    "m8=np.array([[1,0,0],\n",
    "             [1,0,0],\n",
    "             [1,1,1]])\n",
    "m9=np.array([[0,0,1],\n",
    "             [0,0,1],\n",
    "             [1,1,1]])\n",
    "\n",
    "m10=np.array([[1,1,1],\n",
    "             [0,0,0],\n",
    "             [0,0,0]])\n",
    "\n",
    "m11=np.array([[0,1,1],\n",
    "             [1,0,0],\n",
    "             [0,0,0]])\n",
    "m12=np.array([[1,1,0],\n",
    "             [0,0,1],\n",
    "             [0,0,0]])\n",
    "m21=np.array([[0,0,0],\n",
    "             [1,0,0],\n",
    "             [0,1,1]])\n",
    "m22=np.array([[0,0,0],\n",
    "             [0,0,1],\n",
    "             [1,1,0]])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 602,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "show_nparray(m4)\n",
    "#temp=[m1,m2,m3,m4,m5,m6,m7,m8,m9]\n",
    "#temp=[m1,m2,m3,m4,m5]\n",
    "#temp=[m3,m3,m5]\n",
    "temp=[m11,m12,m2,m3,m4,m21,m22]\n",
    "mask_set=[]\n",
    "for i in temp:\n",
    "    mask=np.repeat((np.repeat(i,3,axis=0)),3,axis=1)\n",
    "    mask_set.append(mask)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 607,
   "metadata": {},
   "outputs": [],
   "source": [
    "root = \"trainingDigits16x\" #数据文件所在路径\\n\"\n",
    "pathlist = os.listdir(root) # 获取路径下所有数据文件\"\n",
    "\n",
    "random.shuffle(pathlist)\n",
    "test_set=[]\n",
    "for i in range (0,32):\n",
    "    filepath=root+'\\\\'+pathlist[i]\n",
    "    s=pathlist[i]\n",
    "    n=(re.split('_',s))[0]\n",
    "    target=num_bool_dict[int(n)]\n",
    "    input=file2matrix(filepath).reshape(1,256).tolist()[0]\n",
    "    #print(filepath)\n",
    "    test_set.append([input,target])\n",
    "    \n",
    "random.shuffle(pathlist)\n",
    "verify_set=[]\n",
    "for i in range (0,64):\n",
    "    filepath=root+'\\\\'+pathlist[i]\n",
    "    s=pathlist[i]\n",
    "    n=(re.split('_',s))[0]\n",
    "    target=num_bool_dict[int(n)]\n",
    "    input=file2matrix(filepath).reshape(1,256).tolist()[0]\n",
    "    #print(filepath)\n",
    "    verify_set.append([input,target])    "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 608,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "show_nparray(np.array(test_set[0][0]).reshape(16,16))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 609,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "13\n",
      "[6, 4, 3, 4, 9, 0, 9, 6, 8, 6, 9, 3, 1]\n",
      "14\n",
      "[1, 6, 9, 4, 9, 0, 9, 0, 5, 2, 9, 0, 9, 1]\n",
      "10\n",
      "[7, 0, 1, 1, 4, 1, 4, 7, 1, 0]\n",
      "13\n",
      "[6, 5, 9, 0, 1, 9, 0, 9, 2, 2, 1, 1, 1]\n",
      "9\n",
      "[1, 1, 0, 0, 0, 5, 8, 9, 1]\n",
      "14\n",
      "[0, 4, 4, 0, 0, 5, 7, 2, 0, 0, 7, 0, 7, 3]\n"
     ]
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 864x432 with 5 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 864x432 with 5 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 864x432 with 5 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 864x432 with 5 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAssAAABpCAYAAADMQ24XAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDMuMC4xLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvDW2N/gAACzdJREFUeJzt3WmsXVUZh/HnLdQQQQGLCpdJkUEw0Ro1IoitRq1Ki3FCUQQ0+kGjxhGVBMUZE62KAjFEUZlMHWKENpYawhUwwRGMmAqVtF5bikyFglEo9/XD2iduj2e1tb1nuKfPLznp2cPae+2b09z/XWftd0dmIkmSJOl/zRl2ByRJkqRRZViWJEmSKgzLkiRJUoVhWZIkSaowLEuSJEkVhmVJkiSpwrAsSZIkVRiWJUmSpArDsiRJklRhWJYkaQxFxNsi4srW8pqIWNZanoqI+RFxXET8OiLub/49bjg9lkaTYVmSpPE0CZwQEXMi4gBgLnA8QEQcBuwF/BVYDpwHzAOWAssjYt5wuiyNHsOyJEljKDNvBzYD84EFwEpgfUQ8vVm+DjgRuC0zL8nMLZl5BbAaWDKkbksjZ/dhd0CSJPXNJLAQOLx5v4kSlF/QLE8A67rarAMOHFwXpdHmyLIkSeOrE5ZPaN5PUsLygub9BuDQrjaHAOsH10VptEVmDrsPkiSpDyLiSOC3wJ2ZeXhEPB5YS/lmeV9gH+AvwLuBZcDrgG8Ch2fm3UPptDRinIYhSdKYysxbI+JByvxkMvOBiLgduCszHwXuiYjFwNeAC4E1wGKDsvQfjixLkiRJFc5ZliRJkioMy5IkSVKFYVmSJEmqMCxLkiRJFYZlSZIk7ZCIOCciLh12P/rJ0nGSJLVMbzxi1pSJWjQxf4fbrtxw0y5xzlXTP4gdbizhyLIkSZJUZViWJEkaQxFxdERcGxGbIuKWiDipWf+diDg/IpZHxOaIuDEintZqd1xE/Doi7m/+Pa617akRMdm0WwXs13XOYyPil805b46IhYO63n4xLEuSJI2ZiJgLXAlcDTwJeC9wWUQc1exyCvApymPP1wCfa9o9AVgOnAfMA5YCyyNiXtPucsoj1PcDPgOc3jrngU3bzwJPAD4M/Cginti3Cx0Aw7IkSdL4ORbYCzg3Mx/OzGuAqyghGeDHmfmrzNwCXAZ0JoafCNyWmZdk5pbMvAJYDSyJiEOA5wFnZ+a/MvMXlEDecSqwIjNXZOZ0Zq4CfgO8qt8X20+GZUmSpPEzAUxl5nRr3TrgwOb9xtb6f1CCdafduq5jddpNAPdl5kNd2zoOBd7QTMHYFBGbgBcCB+zUlQyZYVmSRkRErI2Il/b5HE+JiIwIqyFJ420DcHBEtLPeIcD67Wh3aNe6Trs7gH0jYs+ubR1TwCWZuU/rtWdmnrtjlzAaDMuSJEnj50bgIeDMiJjb3Gi3BPj+NtqtAI6MiDdHxO4R8UbgGOCqzFxHmVbxqYh4TES8sDlmx6WU6RqLImK3iNgjIhZGxEEzfXGDZFiWJEkaM5n5MHAS8ErgbuAC4LTMXL2NdvcAi4EPAfcAZwKLM/PuZpc3A88H7gU+CXyv1XYKeDVwFnAXZaT5I8zyvOnXcJI0WuZHxFLK16A/o9xpfixlxOYrwEeBR4GzMvNigIjYG/g65ZfiP4CLgM9n5nRE7AZ8ETgDeAD4cvtkTdullBtwpoGLgU9m5qP9vUxJ/ZaZtwALeqw/o2v5WuCg1vL1wHMqx7wdOGEr57yx1zlnM8OyJI2Wk4FXAP8EbqCE3NXA/sDelJtsXgb8MCJ+kpn3UYLy3sBhlFJPV1PmFn4LeCdllOjZlK9kf9R1vu8CdwKHA3tS7pafAr7ZrwuUpNlkVg+LS9IYOi8zN2TmvZSSTJ1yTo8An87MRzJzBfAgcFQzcvxG4OOZuTkz11JGj9/atDsZ+GpmTjXH/ELnRBHxZMpo9Psz86HM/Dtl9PpN/b9MSZodHFmWZqmIeBB4ZvOVmMZHdzmnieb9PU091Pa2vSgPBngM/12+qV0eaoIyUtze1nEoMBe4IyI66+Z07S9JuzRHlmdA8wjJhTN8zDMi4vqZPKbGS2buZVAW5cadR/jvUk/t8lB3AAd3beuYAv4F7Ncq8/T4zHxGPzssSbOJI8szwF8skoYlMx+NiGXA5yLiNMojZj8IfKnZZRnwvoi4ijJn+WOttndExNXAlyPibMrUjqcCB2Xm5CCvYxwsmpi/7Z1m2MoNNw38nDtjGD8jaWcZlqURExFvA16bmUua5TXA7zLz5GZ5ilLX8vfAEZm5Zmid1ah4L+Umv9spNwZeBHy72XYRcCRwM6UaxpeAl7TangacC/wJeFxzjC8OpNfSLDe98Ygcdh80c+bsf1v0Wm9YngERsRZ4B+WRjsdQflm9BvgrcHpm/qbZ72jgQsoNO+spN+T8tNk2j1KyaSHlzveVXed4OuWX4XMotQvPzsxlfb40Dcck8JXmqUtPpswpPR4gIg6jzFP9w/C6p37JzKd0LZ/TWjyotm9TEePUyjG3AB9oXh3nt7bfD7yreUmSujhneeadRHk6zj7AT4FvAETEXMqd7VcDT6KMBF0WEUc17c6nhOwDgLc3L5q2ewKrgMubtqcAF0SE0z/GUDMPeTPlj6oFlD+c1jd/MC0ArsvM6SF2UZKkXYZheeZdn5krmoL+lwDPatYfSxkRPDczH87Mayj1TE9pSj+9DvhEU77pj5Tapx2LgbWZeXFmbsnM31Fqpb5+UBelgZukfMvwoub9tZSgvKBZliRJA2BYnnndZZ/2iIjdaco3dY0Idso7PZEyJWZr5Z2eHxGbOi/gLZSHFGg8dcLyCc37SQzLkiQNnHOWB2cDcHBEzGkF5kOAWylzkLdQyjutbm3rmAImM/Nlg+qshm6S8gjiOzPzbxHxAOWbit0pN/ZJkqQBcGR5cG6klG06MyLmNnWZlwDfb6Zs/Bg4JyIeGxHHAKe32l4FHBkRb23azo2I5zU3DGoMZeatlDJe1zXLD1CqFNzQfF4kSdIAOLI8IJn5cEScBFwAfJxSDeO0zOyMJL+HUg1jI2V0+WLgxU3bzRHxcspI41LKHzk3U2qpakxl5gFdy8/tWu5Z4kZ1wyjzNJtq7+5MX4dxzlXTP/D/gKS+MyzPgFYJp593rV8LRGv5Fsqc017HuItyI1/tHH8GTtzJrkqSJOn/4DQMSZIkqcKwLEmSJFUYliVJkqQKw7IkSZJU4Q1+mvWmNx6R7TvqO3flL5qY/z/vO/t137nf3ndry93tt7a+3Z/t2a+9b/f7Xtt7HXtr59je5W7dP8ft6Ud7fe0Yvc65aGK+FQ4kSSPFsKxZrzuk9Qp/7TDXbtfrOL229wquvdptK3j2Ov72hMhtXWutTXv/WtDfnpJf2xuMe4Xp7p/r1vq7o+XHpFEwjM/vMEoT7oxhlBiUdlZkDrzsqCQNhXWWt846y8UwPic7araFyHH6nMDs+qxo2+bsf1vPz4pzliVJkqQKw7IkSZJUYViWJEmSKgzLkiRJUoVhWZIkSaqwdJykXUbtTud+WjU96DPuuGH0dTb9fCTtmhxZliRJkioMy5IkSVKFYVmSJEmqMCxLkiRJFYZlSZIkqcKwLEmSJFVYOk6SpCFbNDF/2F0YaSs33DTsLvQ0jHKUGjxHliVJkqQKw7IkSZJUYViWJEmSKgzLkiRJUoVhWZIkSaowLEuSJEkVhmVJkiSpwrAsSZIkVRiWJUmSpArDsiRJklRhWJYkSZIqDMuSJElShWFZkiRJqjAsS5IkSRWRmcPugyRJkjSSHFmWJEmSKgzLkiRJUoVhWZIkSaowLEuSJEkVhmVJkiSpwrAsSZIkVRiWJUmSpArDsiRJklRhWJYkSZIqDMuSJElShWFZkiRJqjAsS5IkSRWGZUmSJKnCsCxJkiRVGJYlSZKkCsOyJEmSVGFYliRJkioMy5IkSVKFYVmSJEmqMCxLkiRJFYZlSZIkqcKwLEmSJFUYliVJkqSKfwMnYrrVz2qQaAAAAABJRU5ErkJggg==\n",
      "text/plain": [
       "<Figure size 864x432 with 5 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 864x432 with 5 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "#multi convolution + neurol network\n",
    "for k in range(0,6):\n",
    "    max=0\n",
    "    bl1=boolean_net.booleannet('bl.db',448,8,4)\n",
    "#train\n",
    "\n",
    "    for j in range(0,20):\n",
    "        #bl1=boolean_net.booleannet('bl.db',320,8,4)\n",
    "        random.shuffle(test_set)\n",
    "\n",
    "        for i in test_set:   \n",
    "            temp=np.array(i[0]).reshape(16,16)\n",
    "            res=multi_convolution(temp,mask_set)\n",
    "            res=list(res.flatten())\n",
    "            bl1.train(res,i[1])\n",
    "            bl1.feedforward()\n",
    "\n",
    "        #test\n",
    "        right=0\n",
    "        right_list=[]\n",
    "        for i in verify_set:\n",
    "            temp=np.array(i[0]).reshape(16,16)\n",
    "            res=multi_convolution(temp,mask_set)\n",
    "            res=list(res.flatten())  \n",
    "            bl1.inode=res\n",
    "            bl1.feedforward()\n",
    "            target = bool_list.index(i[1])\n",
    "            try:\n",
    "                result = bool_list.index(bl1.onode)\n",
    "            except:\n",
    "                result ='not_in_list'\n",
    "            #print()    \n",
    "            if bl1.onode==i[1]:\n",
    "                #print('target: ',target , '  result: ',result,' right')\n",
    "                right_list.append(target)\n",
    "                right+=1\n",
    "            else:\n",
    "                pass\n",
    "                #print('target: ',target , '  result: ',result,' wrong')\n",
    "        if right>max:\n",
    "            max=right\n",
    "            max_right_list=right_list\n",
    "            bl_max=bl1\n",
    "    print (max)\n",
    "    print(max_right_list)\n",
    "    show_nn(bl_max)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 538,
   "metadata": {},
   "outputs": [],
   "source": [
    "vy=[True,True,True,True]\n",
    "\n",
    "mask=np.array(vy)\n",
    "vmask=mask.reshape((2,2))\n",
    "\n",
    "#plt.imshow(vmask)\n",
    "\n",
    "root = \"trainingDigits\" #数据文件所在路径\\n\"\n",
    "transroot=\"trainingDigits16x\"\n",
    "pathlist = os.listdir(root) # 获取路径下所有数据文件\"\n",
    "#random.shuffle(pathlist)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {},
   "outputs": [],
   "source": [
    "for i in range(0,len(pathlist)):\n",
    "    #fig,axs=plt.subplots(nrows=1, ncols=2, figsize=(12, 6))\n",
    "\n",
    "\n",
    "    mx=file2matrix((root+'\\\\'+pathlist[i]))\n",
    "    #plt.imshow(mx)\n",
    "    #axs[0].imshow(mx,vmin=0,vmax=1)\n",
    "    #axs[0].set_axis_off()\n",
    "    #矩阵类似卷积计算\n",
    "\n",
    "    #准备矩阵\n",
    "\n",
    "    x=np.vsplit(mx, 16)\n",
    "\n",
    "    y=[np.hsplit(a,16) for a in x]\n",
    "\n",
    "    #y[0][0]\n",
    "\n",
    "    #y[0][1].flatten().tolist()\n",
    "\n",
    "    #准备子矩阵\n",
    "    temp=[y[i][j] for i in range(0,16)\n",
    "         for j in range(0,16)]\n",
    "\n",
    "\n",
    "\n",
    "    #计算出类似卷积结果矩阵（16x16）\n",
    "    res=[boolean.otimes_bv_bv(u.flatten().tolist(),vy) for u in temp  ]\n",
    "\n",
    "    res=np.array(res).reshape((16,16))\n",
    "    #print([to_string_boollist(x.tolist()) for x in res],'\\n')\n",
    "    with open((transroot+'\\\\'+pathlist[i]),'w') as f:\n",
    "        for x in res:\n",
    "            f.write(to_string_boollist(x.tolist())+'\\n')\n",
    "            #f.write('\\n')\n",
    "            \n",
    "        \n",
    "\n",
    "    #plt.imshow(res)\n",
    "    #axs[1].imshow(res,vmin=0,vmax=1)\n",
    "    #axs[1].set_axis_off()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 65,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0000011100000000\n",
      "0000111110000000\n",
      "0000111111000000\n",
      "0000110111000000\n",
      "0000011001100000\n",
      "0000011011100000\n",
      "0000000011100000\n",
      "0000000011100000\n",
      "0000000011100000\n",
      "0000000011100000\n",
      "0000000111000000\n",
      "0000001111000000\n",
      "0000011111000000\n",
      "0000111111111100\n",
      "0000111111111100\n",
      "0000111111111110\n"
     ]
    }
   ],
   "source": [
    "with open((transroot+pathlist[i]),'w') as f:\n",
    "    for x in res:\n",
    "        print(to_string_boollist(x.tolist()))\n",
    "        f.write(to_string_boollist(x.tolist()))"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
